﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Net;

namespace eSYSU.Web.Common
{
    /// <summary>
    /// 绘图类，生成验证码图片、缩略图、统计图等图片
    /// </summary>
    public class ImageHelper
    {
        string sErr = "";

        public ImageHelper()
        {
            //
            //TODO: 在此处添加构造函数逻辑
            //
        }


        #region 生成指定长度的随机验证码
        /// <summary>
        /// 生成指定长度的随机验证码
        /// </summary>
        /// <param name="numLength">验证码长度</param>
        /// <returns>返回生成的验证码字符串</returns>
        public string CreateRandomNum(int iNumLength)
        {
            string sRegion = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
            char[] caRegion = sRegion.ToCharArray();
            System.Text.StringBuilder sbRandomNum = new System.Text.StringBuilder();
            Random codeRand = new Random();
            for (int i = 0; i < iNumLength; i++)
            {
                sbRandomNum.Append(caRegion[codeRand.Next(caRegion.Length - 1)]);
            }
            return sbRandomNum.ToString();
        }
        #endregion


        #region 基于输入的字符串生成指定格式的验证码图片
        /// <summary>
        /// 基于输入的字符串生成指定格式的验证码图片
        /// </summary>
        /// <param name="sValidateNum">用于生成图片的字符串</param>
        /// <param name="iImageFormat">验证码图片的格式：2为GIF，3为PNG，4为JPEG</param>
        public void CreateCodeImage(string sValidateNum, int iImageFormat)
        {
            if (sValidateNum == null || sValidateNum.Trim() == string.Empty) return;

            //生成Bitmap图像
            System.Drawing.Bitmap codeImage = new System.Drawing.Bitmap(sValidateNum.Length * 20 + 15, 40);
            Graphics g = Graphics.FromImage(codeImage);

            //往Bitmap添加内容，包括验证码、干扰线和噪点
            try
            {
                Random rand = new Random();
                //设置图片背景色
                g.Clear(Color.White);
                //生成干扰线
                for (int i = 1; i < 6; i++)
                {
                    int x1 = rand.Next(codeImage.Width);
                    int y1 = rand.Next(codeImage.Height);
                    int x2 = rand.Next(codeImage.Width);
                    int y2 = rand.Next(codeImage.Height);
                    g.DrawLine(new Pen(Color.Brown, 1), 0, y1, codeImage.Width, y2);
                }

                //生成加粗、斜体和颜色渐变的验证码文字
                Font codeFont = new Font("Arial", 20, (FontStyle.Bold | FontStyle.Italic));
                System.Drawing.Drawing2D.LinearGradientBrush codeBrush = new System.Drawing.Drawing2D.LinearGradientBrush(new Rectangle(0, 0, codeImage.Width, codeImage.Height), Color.Blue, Color.DarkRed, 1.2f, true);
                g.DrawString(sValidateNum, codeFont, codeBrush, 5, 4);

                //生成噪点
                for (int i = 0; i < 50; i++)
                {
                    int x = rand.Next(codeImage.Width);
                    int y = rand.Next(codeImage.Height);
                    codeImage.SetPixel(x, y, Color.FromArgb(rand.Next()));
                }

                //将验证码图像输出到内存流
                System.Drawing.Imaging.ImageFormat ifType = new System.Drawing.Imaging.ImageFormat(System.Guid.Empty);
                string sImageFormat = "";
                switch (iImageFormat)
                {
                    case 2:
                        ifType = System.Drawing.Imaging.ImageFormat.Gif;
                        sImageFormat = "Gif";
                        break;
                    case 3:
                        ifType = System.Drawing.Imaging.ImageFormat.Png;
                        sImageFormat = "Png";
                        break;
                    case 4:
                        ifType = System.Drawing.Imaging.ImageFormat.Jpeg;
                        sImageFormat = "Jpeg";
                        break;
                    default:
                        sErr = "格式输入有误，请检查后重试。";
                        return;
                }
                System.IO.MemoryStream codeImageMS = new System.IO.MemoryStream();
                codeImage.Save(codeImageMS, ifType);
                System.Web.HttpContext.Current.Response.ClearContent();
                System.Web.HttpContext.Current.Response.ContentType = "image/" + sImageFormat;
                System.Web.HttpContext.Current.Response.BinaryWrite(codeImageMS.ToArray());
            }
            catch (Exception ex)
            {
                sErr = ex.Message;
            }
            finally
            {
                g.Dispose();
                codeImage.Dispose();
            }
        }
        #endregion


        #region 生成饼状统计图
        /// <summary>
        /// 生成饼状统计图
        /// </summary>
        /// <param name="items">选项数组</param>
        /// <param name="itemCount">各个选项对应的投票数数组</param>
        /// <param name="title">统计图名称</param>
        /// <param name="sizeW">统计图的宽度（像素）</param>
        /// <param name="sizeH">统计图的高度（像素）</param>
        /// <param name="iType">统计图的格式，2为GIF，3为PNG，4为JPEG</param>
        public void CreatePieImage(string[] items, string[] itemCount, string title, int sizeW, int sizeH, int iType)
        {
            Bitmap pieBitmap = new Bitmap(sizeW, sizeH);
            Graphics g = Graphics.FromImage(pieBitmap);

            int length = itemCount.Length;
            Single total = 0;

            for (int i = 0; i < length; i++)
            {
                total += Convert.ToSingle(itemCount[i]);
            }

            try
            {
                g.Clear(Color.White);
                Pen piePen = new Pen(Color.Red);
                Brush[] pieBrushes = new Brush[length + 1];
                Brush myBrush = new SolidBrush(Color.White);

                Random rgbRandom = new Random();
                for (int i = 0; i < length; i++)
                {
                    int red = rgbRandom.Next(255);
                    int green = rgbRandom.Next(255);
                    int blue = rgbRandom.Next(255);
                    pieBrushes[i] = new SolidBrush(Color.FromArgb(red, green, blue));
                }
                Font font1 = new Font("幼圆", 12, FontStyle.Bold);
                Font font2 = new Font("Arial", 8);
                g.FillRectangle(myBrush, 0, 0, 370, 350);   //绘制背景
                g.DrawString(title, font1, new SolidBrush(Color.Indigo), new Point(40, 20));  //绘制标题
                float[] pieAngle = new float[length];
                for (int i = 0; i < length; i++)
                {
                    pieAngle[i] = Convert.ToSingle(360 * (Convert.ToSingle(itemCount[i]) / total));   //计算各项占的百分比
                }
                float angle = 0;
                //绘制饼图
                for (int i = 0; i < length; i++)
                {
                    g.FillPie(pieBrushes[i], 100, 60, 180, 180, angle, pieAngle[i]);
                    angle += pieAngle[i];
                }

                g.DrawRectangle(piePen, 50, 255, 260, 50 + length * 14);   //绘制选项边框

                //绘制各个选项的内容及得票数
                for (int i = 0; i < length; i++)
                {
                    g.FillRectangle(pieBrushes[i], 85, 265 + i * 20, 20, 10);
                    g.DrawString(items[i] + "     " + itemCount[i] + "票", font2, new SolidBrush(Color.Indigo), 120, 265 + i * 20);
                }

                //将Image对象输出到内存流
                System.Drawing.Imaging.ImageFormat ifType = new System.Drawing.Imaging.ImageFormat(System.Guid.Empty);
                string sImageFormat = "";
                switch (iType)
                {
                    case 2:
                        ifType = System.Drawing.Imaging.ImageFormat.Gif;
                        sImageFormat = "Gif";
                        break;
                    case 3:
                        ifType = System.Drawing.Imaging.ImageFormat.Png;
                        sImageFormat = "Png";
                        break;
                    case 4:
                        ifType = System.Drawing.Imaging.ImageFormat.Jpeg;
                        sImageFormat = "Jpeg";
                        break;
                    default:
                        sErr = "格式输入有误，请检查后重试。";
                        return;
                }
                System.IO.MemoryStream msImage = new System.IO.MemoryStream();
                pieBitmap.Save(msImage, ifType);
                System.Web.HttpContext.Current.Response.ClearContent();
                System.Web.HttpContext.Current.Response.ContentType = "image/" + sImageFormat;
                System.Web.HttpContext.Current.Response.BinaryWrite(msImage.ToArray());
            }
            catch (Exception ex)
            {
                sErr = ex.Message;
            }
            finally
            {
                g.Dispose();
            }
        }
        #endregion


        #region 生成缩略图
        /// <summary>
        /// 生成缩略图
        /// </summary>
        /// <param name="originalImagePath">原来图片的绝对路径及文件名</param>
        /// <param name="thumbnailPath">缩略图保存的绝对路径及文件名</param>
        /// <param name="width">缩略图长度</param>
        /// <param name="height">缩略图宽度</param>
        public static void CreateThumbnail(string originalImagePath, string thumbnailPath, int width, int height)
        {
            //获取原始图片 
            System.Drawing.Image originalImage = System.Drawing.Image.FromFile(originalImagePath);
            //原始图片写入画布坐标和宽高(用来设置裁减溢出部分) 
            int x = 0;
            int y = 0;
            int ow = originalImage.Width;
            int oh = originalImage.Height;
            //缩略图画布宽高 
            int towidth = width;
            int toheight = width * oh / ow;  //按原图比例设置图片高度
            //原始图片画布,设置写入缩略图画布坐标和宽高(用来原始图片整体宽高缩放) 
            int bg_x = 0;
            int bg_y = 0;
            int bg_w = towidth;
            int bg_h = toheight;
            //倍数变量 
            double multiple = 0;
            //获取宽长的或是高长与缩略图的倍数
            if (originalImage.Width >= originalImage.Height)
                multiple = (double)originalImage.Width / (double)width;
            else
                multiple = (double)originalImage.Height / (double)height;
            //上传的图片的宽和高小等于缩略图 
            if (ow <= width && oh <= height)
            {
                //缩略图按原始宽高 
                bg_w = originalImage.Width;
                bg_h = originalImage.Height;
                //空白部分用背景色填充 
                bg_x = Convert.ToInt32(((double)towidth - (double)ow) / 2);
                bg_y = Convert.ToInt32(((double)toheight - (double)oh) / 2);
            }
            //上传的图片的宽和高大于缩略图 
            else
            {
                //宽高按比例缩放 
                bg_w = Convert.ToInt32((double)originalImage.Width / multiple);
                bg_h = Convert.ToInt32((double)originalImage.Height / multiple);
                //空白部分用背景色填充 
                bg_y = Convert.ToInt32(((double)toheight - (double)bg_h) / 2);
                bg_x = Convert.ToInt32(((double)towidth - (double)bg_w) / 2);
            }
            //新建一个bmp图片,并设置缩略图大小.
            System.Drawing.Image bitmap = new System.Drawing.Bitmap(towidth, toheight);
            //新建一个画板
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(bitmap);
            //设置高质量插值法
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
            //设置高质量,低速度呈现平滑程度 
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            //清空画布并设置背景色 
            g.Clear(Color.White);
            //在指定位置并且按指定大小绘制原图片的指定部分 
            //第一个System.Drawing.Rectangle是原图片的画布坐标和宽高,第二个是原图片写在画布上的坐标和宽高,最后一个参数是指定数值单位为像素 
            g.DrawImage(originalImage, new System.Drawing.Rectangle(bg_x, bg_y, bg_w, bg_h), new System.Drawing.Rectangle(x, y, ow, oh), System.Drawing.GraphicsUnit.Pixel);
            try
            {
                //获取图片类型 
                string fileExtension = System.IO.Path.GetExtension(originalImagePath).ToLower();
                //string fileExtension = ".png";
                //按原图片类型保存缩略图片,不按原格式图片会出现模糊,锯齿等问题. 
                switch (fileExtension)
                {
                    case ".gif": bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Gif); break;
                    case ".jpg": bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Jpeg); break;
                    case ".png": bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Png); break;
                    case ".bmp": bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Bmp); break;
                    default: bitmap.Save(thumbnailPath, System.Drawing.Imaging.ImageFormat.Jpeg); break;
                }
            }
            catch (System.Exception e)
            {
                throw e;
            }
            finally
            {
                originalImage.Dispose();
                bitmap.Dispose();
                g.Dispose();
            }
        }
        #endregion


        #region 自动下载远程图片到本地
        /// <summary>
        /// 自动下载远程图片到本地
        /// </summary>
        /// <param name="savedir">图片的本地保存路径</param>
        /// <param name="imgpath">需保存的远程图片路径</param>
        /// <param name="imgName">本地图片名（不包含图片扩展名）</param>
        /// <param name="imgExt">图片扩展名</param>
        /// <returns>保存结果 (本地地址/Null)</returns>
        public static string DownLoadRemoteImage(string imgpath, string savedir, string imgName, string imgExt)
        {
            if (string.IsNullOrEmpty(imgpath))
                return string.Empty;
            else
            {
                string saveFilePath = string.Empty; //图片本地保存路径
                //imgName = imgpath.Substring(imgpath.LastIndexOf("/"), imgpath.Length - imgpath.LastIndexOf("/"));
                //imgExt = imgpath.Substring(imgpath.LastIndexOf("."), imgpath.Length - imgpath.LastIndexOf("."));

                imgName = imgName + imgExt;

                saveFilePath = System.Web.HttpContext.Current.Server.MapPath(savedir);
                if (!Directory.Exists(saveFilePath))
                    Directory.CreateDirectory(saveFilePath);

                try
                {
                    WebRequest wreq = WebRequest.Create(imgpath);
                    wreq.Timeout = 10000;//超时时间
                    HttpWebResponse wresp = (HttpWebResponse)wreq.GetResponse();
                    Stream s = wresp.GetResponseStream();
                    System.Drawing.Image img;
                    img = System.Drawing.Image.FromStream(s);
                    switch (imgExt.ToLower())
                    {
                        case ".gif":
                            img.Save(saveFilePath + imgName, ImageFormat.Gif);
                            break;
                        case ".jpg":
                        case ".jpeg":
                            img.Save(saveFilePath + imgName, ImageFormat.Jpeg);
                            break;
                        case ".png":
                            img.Save(saveFilePath + imgName, ImageFormat.Png);
                            break;
                        case ".bmp":
                            img.Save(saveFilePath + imgName, ImageFormat.Bmp);
                            break;
                        default:
                            break;
                    }

                    img.Dispose();
                    s.Dispose();

                    return savedir + imgName;
                }
                catch
                {
                    return string.Empty;
                }
            }
        }


        /// <summary>
        /// HTML中的远程图片本地化，生成三种大小的缩略图，并返回处理后的HTML代码
        /// </summary>
        /// <param name="sHtml">需处理的HTML代码</param>
        /// <returns>图片路径本地化后的HTML代码</returns>
        public static string HtmlRemoteImageHandler(string sHtml)
        {
            List<string> imgList = StringHelper.AddHostToUrl(StringHelper.GetImageSrcInHtml(sHtml), "");
            string imgSavePath = "~/Uploads/images/" + DateTime.Now.Year.ToString() + "/" + DateTime.Now.Month.ToString() + "/";
            string imgName = "newsImg_" + DateTime.Now.ToString("yyyyMMddHHmmssfff");  //图片的本地文件名
            string imgSaveAP = System.Web.HttpContext.Current.Server.MapPath(imgSavePath); //转换为绝对路径

            if (imgList.Count > 0)
            {
                foreach (string img in imgList)
                {
                    string imgExt = System.IO.Path.GetExtension(img).ToLower(); //获取图片的扩展名
                    string localPath = DownLoadRemoteImage(img, imgSavePath, imgName, imgExt);   //执行远程图片保存方法，并保存返回的本地图片路径
                    string hostUrl = localPath.Substring(1); //本地图片的URL相对地址

                    localPath = System.Web.HttpContext.Current.Server.MapPath(localPath); //转换为绝对路径

                    if (File.Exists(localPath))
                    {
                        CreateThumbnail(localPath, imgSaveAP + imgName + "_thumb480" + imgExt, 480, 360);
                        CreateThumbnail(localPath, imgSaveAP + imgName + "_thumb240" + imgExt, 240, 180);
                        CreateThumbnail(localPath, imgSaveAP + imgName + "_thumb120" + imgExt, 120, 90);

                        sHtml = sHtml.Replace(img, hostUrl); //替换HTML中的远程图片地址为本地地址
                    }
                }
            }
            return sHtml;
        }
        #endregion
    }
}